#pragma once
#include "libs.cpp"
#include "compile_string.cpp"
namespace json {
    namespace types {
        struct number {};
        struct string {};
        template <typename ...Ts>
        struct array {};
        template <typename First, typename Second>
        struct object_pair {};
    };
    namespace detail {
        template <typename T>
        constexpr bool is_object_pair_v = false;
        template <typename ...Ts>
        constexpr bool is_object_pair_v<types::object_pair<Ts...>> = true;
        template <typename T>
        concept object_pair_type = is_object_pair_v<T>;
        template <typename ...Ts>
        class typelist;
        template <size_t, typename ...>
        struct get_impl;
        template <size_t N, typename T, typename ...Ts>
        struct get_impl<N, T, Ts...> {
            using type = typename get_impl<N - 1, Ts...>::type;
        };
        template <typename T, typename ...Ts>
        struct get_impl<0, T, Ts...> {
            using type = T;
        };
        template <typename ...Ts>
        class typelist {
            template <typename T>
            struct concat_back_impl;
            template <template <typename ...> class T, typename ...Ts2>
            struct concat_back_impl<T<Ts2...>> {
                using type = typelist<Ts..., Ts2...>;
            };
            template <typename T>
            struct concat_front_impl;
            template <template <typename ...> class T, typename ...Ts2>
            struct concat_front_impl<T<Ts2...>> {
                using type = typelist<Ts2..., Ts...>;
            };
        public:
            template <template <typename ...> class T>
            using as = T<Ts...>;
            template <typename ...Ts2>
            using push_back = typelist<Ts..., Ts2...>;
            template <typename ...Ts2>
            using push_front = typelist<Ts2..., Ts...>;
            template <typename T>
            using concat_back = typename concat_back_impl<T>::type;
            template <typename T>
            using concat_front = typename concat_front_impl<T>::type;
            template <size_t S>
            using get = get_impl<S, Ts...>;
        };
    };
    namespace types {
        template <detail::object_pair_type ...Ts>
        struct object {};
    };
};
